﻿#include "FITKMeshGenerateProcessorGmsh.h"
#include "gmsh.h"
#include "FITK_Interface/FITKInterfaceModel/FITKComponentManager.h"
#include "FITK_Interface/FITKInterfaceModel/FITKUnstructuredMesh.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementFactory.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
#include "FITK_Interface/FITKInterfaceModel/FITKModelEnum.h"
#include <QDir>

namespace Gmsh
{
    FITKMeshGenerateProcessorGmsh::FITKMeshGenerateProcessorGmsh()
    {

    }

    FITKMeshGenerateProcessorGmsh::~FITKMeshGenerateProcessorGmsh()
    {

    }

    void FITKMeshGenerateProcessorGmsh::start(QStringList info /*= QStringList()*/)
    {
        _meshData = dynamic_cast<Interface::FITKUnstructuredMesh*>(this->_dataObject.value("MeshData"));
        _setDataMgr = dynamic_cast<Interface::FITKComponentManager*>(this->_dataObject.value("SetManager"));
        if (!_meshData || !_setDataMgr)
        {
            return;
        }
        //提取划分的网格数据
        this->extractAllNodes();
        this->extractAllElement();
        this->meshPartitionDataExtract();
    }

    void FITKMeshGenerateProcessorGmsh::extractAllNodes()
    {
        if (!_meshData) return;
        // Nodes
        int dim = -1;
        int tag = -1;
        bool includeBoundary = false;
        std::vector<size_t> nodeTags;
        std::vector<double> coord, parametricCoord;
        gmsh::model::mesh::getNodes(nodeTags, coord, parametricCoord, dim, tag, includeBoundary, true);
        if (nodeTags.size() != coord.size() / 3)return;
        
        //获取点的数据
        for (unsigned int i = 0; i < nodeTags.size(); ++i)
            _meshData->addNode(nodeTags[i], coord[3 * i], coord[3 * i + 1], coord[3 * i + 2]);
    }

    void FITKMeshGenerateProcessorGmsh::extractAllElement()
    {
        if (!_meshData) return;
        //Elements
        int dim = -1;
        int tag = -1;
        std::vector<int> elementTypes;
        std::vector<std::vector<size_t> > elementTags, nodeTagss;
        gmsh::model::mesh::getElements(elementTypes, elementTags, nodeTagss, dim, tag);

        //获取单元的数据
        for (unsigned int j = 0; j < elementTypes.size(); j++)
        {
            std::string eleTypeName;
            int dim, order, numNodes, numPrimaryNodes;
            std::vector<double> localNodeCoord;
            gmsh::model::mesh::getElementProperties(elementTypes[j], eleTypeName, dim, order, numNodes, localNodeCoord, numPrimaryNodes);
            //获取网格类型
            Interface::FITKModelEnum::FITKEleType type = Interface::FITKModelEnum::FITKEleType::EleNone;
            if (elementTypes[j] == 1)
                type = Interface::FITKModelEnum::FITKEleType::Line2;
            else if (elementTypes[j] == 2 && order == 1)
                type = Interface::FITKModelEnum::FITKEleType::Tri3;
            else if (elementTypes[j] == 3 && order == 1)
                type = Interface::FITKModelEnum::FITKEleType::Quad4;
            else if (elementTypes[j] == 4 && order == 1)
                type = Interface::FITKModelEnum::FITKEleType::Tet4;
            else if (elementTypes[j] == 5 && order == 1)
                type = Interface::FITKModelEnum::FITKEleType::Hex8;
            if (type == Interface::FITKModelEnum::FITKEleType::EleNone)continue;
            for (unsigned int i = 0; i < elementTags[j].size(); ++i)
            {
                //设置单元
                Interface::FITKAbstractElement* element = Interface::FITKElementFactory::createElement(type);
                if (!element) return;
                element->setEleID(elementTags[j][i]);
                for (unsigned int k = 0; k < numNodes; ++k)
                {
                    element->setNodeID(k, nodeTagss[j][i * numNodes + k]);
                }
            }
        }
    }

    void FITKMeshGenerateProcessorGmsh::meshPartitionDataExtract()
    {
        if (!_setDataMgr || !_meshData) return;
        gmsh::vectorpair entities;
        //获取当前模型中的所有实体,包含<dim, tag>属性
        gmsh::model::getEntities(entities);
        int i = 0;
        for (gmsh::vectorpair::iterator iter = entities.begin(); iter != entities.end(); ++iter, ++i)
        {
            //获取实体的维度和标签
            int dim = iter->first;
            int tag = iter->second;
            //get the mesh nodes for each elementary entity
            std::vector<size_t> nodeTags;
            std::vector<double> nodeCoords, nodeParams;
            //nodeCoords为节点的xyz坐标，nodeParams为节点的参数坐标(u1,v1,u2,v2）
            gmsh::model::mesh::getNodes(nodeTags, nodeCoords, nodeParams, dim, tag, true, true);
            //设置点集
            Interface::FITKModelSet* set = nullptr;
            if (!nodeTags.empty())
            {
                set = new Interface::FITKModelSet();
                set->setModelSetType(Interface::FITKModelEnum::FITKModelSetType::FMSNode);
                set->setModel(_meshData->getDataObjectID());
                _setDataMgr->appendDataObj(set);
            }
            for (unsigned int j = 0; j < nodeTags.size(); ++j)
            {
                //获取点的数据
                set->appendMember(nodeTags[j]);
            }
            set = nullptr;
            // 如果是点属性就跳过
            if (dim == 0) continue;
            // get the mesh elements for each elementary entity
            std::vector<int> elementTypes;
            std::vector<std::vector<size_t> > elementTags, nodeTagss;
            //比如dim=2, tag=13,这个表面有90个单元，那么elemTags[0]是90元素的向量，比如elemTags[0][0]为第一个三角面元的编号，而elemNodeTags[0][0]-[0][2]是第一个三角面元三顶点的编号。
            gmsh::model::mesh::getElements(elementTypes, elementTags, nodeTagss, dim, tag);
            //设置单元集
            if (!nodeTags.empty())
            {
                set = new Interface::FITKModelSet();
                set->setModelSetType(Interface::FITKModelEnum::FITKModelSetType::FMSElem);
                set->setModel(_meshData->getDataObjectID());
                _setDataMgr->appendDataObj(set);
            }
            for (unsigned int j = 0; j < elementTypes.size(); j++)
            {
                std::string eleTypeName;
                int dim, order, numNodes, numPrimaryNodes;
                std::vector<double> localNodeCoord;
                gmsh::model::mesh::getElementProperties(elementTypes[j], eleTypeName, dim, order, numNodes, localNodeCoord, numPrimaryNodes);
                //获取网格类型
                Interface::FITKModelEnum::FITKEleType type = Interface::FITKModelEnum::FITKEleType::EleNone;
                if (elementTypes[j] == 1)
                    type = Interface::FITKModelEnum::FITKEleType::Line2;
                else if (elementTypes[j] == 2 && order == 1)
                    type = Interface::FITKModelEnum::FITKEleType::Tri3;
                else if (elementTypes[j] == 3 && order == 1)
                    type = Interface::FITKModelEnum::FITKEleType::Quad4;
                else if (elementTypes[j] == 4 && order == 1)
                    type = Interface::FITKModelEnum::FITKEleType::Tet4;
                else if (elementTypes[j] == 5 && order == 1)
                    type = Interface::FITKModelEnum::FITKEleType::Hex8;
                if (type == Interface::FITKModelEnum::FITKEleType::EleNone)continue;
                if (dim == 0)continue;
                for (unsigned int k = 0; k < elementTags[j].size(); ++k)
                {
                    //获取单元数据
                    set->appendMember(elementTags[j][k]);
                }
            }
            set = nullptr;
        }
    }
}
